﻿using static Vanara.PInvoke.Ole32;
using static Vanara.PInvoke.Shell32;

namespace Vanara.PInvoke;

public static partial class SearchApi
{
	/// <summary>
	/// Exposes methods that create and modify search folders. The Set methods are called first to set up the parameters of the search.
	/// When not called, default values will be used instead. ISearchFolderItemFactory::GetIDList and
	/// ISearchFolderItemFactory::GetShellItem return the two forms of the search specified by these parameters.
	/// </summary>
	/// <remarks>To implement this interface use class ID <c>CLSID_SearchFolderItemFactory</c>.</remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nn-shobjidl_core-isearchfolderitemfactory
	[PInvokeData("shobjidl_core.h", MSDNShortId = "a684b373-6de4-4b4a-bbae-85e1c5a7e04a")]
	[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("a0ffbc28-5482-4366-be27-3e81e78e06c2"), CoClass(typeof(SearchFolderItemFactory))]
	public interface ISearchFolderItemFactory
	{
		/// <summary>Sets the search folder display name, as specified.</summary>
		/// <param name="pszDisplayName">
		/// <para>Type: <c>LPCWSTR</c></para>
		/// <para>A pointer to a folder display name as a Unicode string.</para>
		/// </param>
		/// <remarks>Calling this method is required. A display name must be set.</remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setdisplayname
		// HRESULT SetDisplayName( LPCWSTR pszDisplayName );
		void SetDisplayName([MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName);

		/// <summary>Sets a search folder type ID, as specified.</summary>
		/// <param name="ftid">
		/// <para>Type: <c>FOLDERTYPEID</c></para>
		/// <para>The FOLDERTYPEID, which is a <c>GUID</c> used to identify folder types within the system. The default is <c>FOLDERTYPID_Library</c></para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setfoldertypeid
		// HRESULT SetFolderTypeID( FOLDERTYPEID ftid );
		void SetFolderTypeID(Guid ftid);

		/// <summary>
		/// Sets folder logical view mode. The default settings are based on the which is set by the
		/// ISearchFolderItemFactory::SetFolderTypeID method.
		/// </summary>
		/// <param name="flvm">
		/// <para>Type: <c>FOLDERLOGICALVIEWMODE</c></para>
		/// <para>The FOLDERLOGICALVIEWMODE value.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setfolderlogicalviewmode
		// HRESULT SetFolderLogicalViewMode( FOLDERLOGICALVIEWMODE flvm );
		void SetFolderLogicalViewMode(FOLDERLOGICALVIEWMODE flvm);

		/// <summary>
		/// Sets the search folder icon size, as specified. The default settings are based on the which is set by the
		/// ISearchFolderItemFactory::SetFolderTypeID method.
		/// </summary>
		/// <param name="iIconSize">
		/// <para>Type: <c>int</c></para>
		/// <para>The icon size.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-seticonsize
		// HRESULT SetIconSize( int iIconSize );
		void SetIconSize(int iIconSize);

		/// <summary>
		/// Creates a new column list whose columns are all visible, given an array of PROPERTYKEY structures. The default is based on <c>FolderTypeID</c>.
		/// </summary>
		/// <param name="cVisibleColumns">
		/// <para>Type: <c>UINT</c></para>
		/// <para>The number of array elements.</para>
		/// </param>
		/// <param name="rgKey">
		/// <para>Type: <c>const PROPERTYKEY*</c></para>
		/// <para>A pointer to an array of PROPERTYKEY structures.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setvisiblecolumns
		// HRESULT SetVisibleColumns( UINT cVisibleColumns, const PROPERTYKEY *rgKey );
		void SetVisibleColumns(uint cVisibleColumns, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] PROPERTYKEY[] rgKey);

		/// <summary>Creates a list of sort column directions, as specified.</summary>
		/// <param name="cSortColumns">
		/// <para>Type: <c>UINT</c></para>
		/// <para>The number of sort columns.</para>
		/// </param>
		/// <param name="rgSortColumns">
		/// <para>Type: <c>SORTCOLUMN*</c></para>
		/// <para>A pointer to an array of SORTCOLUMN structures containing sort direction. The default is <c>PKEY_ItemNameDisplay</c>.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setsortcolumns
		// HRESULT SetSortColumns( UINT cSortColumns, SORTCOLUMN *rgSortColumns );
		void SetSortColumns(uint cSortColumns, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] SORTCOLUMN[] rgSortColumns);

		/// <summary>Sets a group column, as specified. If no group column is specified, no grouping occurs.</summary>
		/// <param name="keyGroup">
		/// <para>Type: <c>REFPROPERTYKEY</c></para>
		/// <para>A reference to a group column PROPERTYKEY.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setgroupcolumn
		// HRESULT SetGroupColumn( REFPROPERTYKEY keyGroup );
		void SetGroupColumn(in PROPERTYKEY keyGroup);

		/// <summary>
		/// Creates a list of stack keys, as specified. If this method is not called, by default the folder will not be stacked.
		/// </summary>
		/// <param name="cStackKeys">
		/// <para>Type: <c>UINT</c></para>
		/// <para>The number of stacks keys.</para>
		/// </param>
		/// <param name="rgStackKeys">
		/// <para>Type: <c>PROPERTYKEY*</c></para>
		/// <para>A pointer to an array of PROPERTYKEY structures containing stack key information.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setstacks HRESULT
		// SetStacks( UINT cStackKeys, PROPERTYKEY *rgStackKeys );
		void SetStacks(uint cStackKeys, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] PROPERTYKEY[] rgStackKeys);

		/// <summary>Sets search scope, as specified.</summary>
		/// <param name="psiaScope">
		/// <para>Type: <c>IShellItemArray*</c></para>
		/// <para>
		/// A pointer to the list of locations to search. The search will include this location and all its subcontainers. The default is <c>FOLDERID_Profile</c>
		/// </para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setscope HRESULT
		// SetScope( IShellItemArray *psiaScope );
		void SetScope([In] IShellItemArray? psiaScope);

		/// <summary>
		/// Sets the ICondition of the search. When this method is not called, the resulting search will have no filters applied.
		/// </summary>
		/// <param name="pCondition">
		/// <para>Type: <c>ICondition*</c></para>
		/// <para>A pointer to an ICondition interface.</para>
		/// </param>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-setcondition
		// HRESULT SetCondition( ICondition *pCondition );
		void SetCondition([In] ICondition pCondition);

		/// <summary>Gets the search folder as a IShellItem.</summary>
		/// <param name="riid">
		/// <para>Type: <c>REFIID</c></para>
		/// <para>A reference to the desired IID.</para>
		/// </param>
		/// <returns>The IShellItem interface pointer specified in riid.</returns>
		/// <remarks>When the retrieved IShellItem is enumerated, it returns the search results.</remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-getshellitem
		// HRESULT GetShellItem( REFIID riid, void **ppv );
		[return: MarshalAs(UnmanagedType.IUnknown)]
		object? GetShellItem(in Guid riid);

		/// <summary>Gets the search folder as an ITEMIDLIST.</summary>
		/// <returns>
		/// <para>Type: <c>PIDLIST_ABSOLUTE*</c></para>
		/// <para>When this method returns successfully, contains a PIDL.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-isearchfolderitemfactory-getidlist HRESULT
		// GetIDList( PIDLIST_ABSOLUTE *ppidl );
		PIDL GetIDList();
	}

	/// <summary>Extension method to simplify using the <see cref="ISearchFolderItemFactory.GetShellItem"/> method.</summary>
	/// <typeparam name="T">Type of the interface to get.</typeparam>
	/// <param name="sfif">An <see cref="ISearchFolderItemFactory"/> instance.</param>
	/// <returns>Receives the interface pointer requested in <typeparamref name="T"/>.</returns>
	public static T? GetShellItem<T>(this ISearchFolderItemFactory sfif) where T : class => (T?)sfif.GetShellItem(typeof(T).GUID);

	/// <summary>CLSID_SearchFolderItemFactory</summary>
	[PInvokeData("shobjidl_core.h", MSDNShortId = "a684b373-6de4-4b4a-bbae-85e1c5a7e04a")]
	[ComImport, Guid("14010e02-bbbd-41f0-88e3-eda371216584"), ClassInterface(ClassInterfaceType.None)]
	public class SearchFolderItemFactory { }
}